﻿using System;
using System.Collections.Generic;
using System.Text;

using EasyHook;
using SqlMon;
using System.Runtime.InteropServices;
using System.Threading;
namespace SqlMonHook
{
    public class Main : EasyHook.IEntryPoint
    {
        SqlMonInterface Interface;
        LocalHook Hook;
        Stack<String> Queue = new Stack<String>();

        public Main(
            RemoteHooking.IContext InContext,
            String InChannelName)
        {
            // connect to host...
            Interface = RemoteHooking.IpcConnectClient<SqlMonInterface>(InChannelName);
        }

        public void Run(RemoteHooking.IContext InContext, String InChannelName )
        {
            try
            {
                Hook = LocalHook.Create(LocalHook.GetProcAddress(@"H:\oracle\product\10.2.0\db_2\bin\oci.dll", "OCIStmtPrepare"),
                    new DOCIStmtPrepare(OCIStmtPrepare_Hook),
                    this);

                Hook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
            }
            catch (Exception ex)
            {
                Interface.ReportException(ex);

                return;
            }

            Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());

            RemoteHooking.WakeUpProcess();

            //wait for host process termination...
            try
            {
                while (true)
                {
                    Thread.Sleep(500);

                    // transmit newly monitored file accesses...
                    if (Queue.Count > 0)
                    {
                        String[] Package = null;

                        lock (Queue)
                        {
                            Package = Queue.ToArray();

                            Queue.Clear();
                        }

                        Interface.OnPrepare(RemoteHooking.GetCurrentProcessId(), Package);
                    }
                    //else
                    //Interface.Ping();
                }
            }
            catch
            {
                // Ping() will raise an exception if host is unreachable
            }
        }

        static int OCIStmtPrepare_Hook(ref IntPtr stmtp, ref IntPtr errhp, string stmt, int stmt_len, uint language, uint mode)
        {
            //System.Diagnostics.Debugger.Break();
            try
            {
                Main This = (Main)HookRuntimeInfo.Callback;

                lock (This.Queue)
                {
                    This.Queue.Push(stmt);
                }

                //This.Interface.OnCreateFile(RemoteHooking.GetCurrentProcessId(),new string[]{stmt});
            }
            catch
            {
            }

            return OCIStmtPrepare(ref stmtp, ref errhp, stmt, stmt_len, language, mode);
        }

        delegate int DOCIStmtPrepare(ref IntPtr stmtp, ref IntPtr errhp, string stmt, int stmt_len, uint language, uint mode);

        //DLL路径根据注册表获取 TODO...
        [DllImport(@"H:\oracle\product\10.2.0\db_2\bin\oci.dll",
        CharSet = CharSet.None,
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
        static extern int OCIStmtPrepare(ref IntPtr stmtp, ref IntPtr errhp, string stmt, int stmt_len, uint language, uint mode);        
    }
}
